<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Promise</title>
</head>

<body>
  <script>
    // 1.手写promise
    const PENDING = 'pengding',
      FULFILLED = 'fulfilled',
      REJECTED = 'rejected'

    class Mypromise {
      constructor(executor) {
        this.state = PENDING
        this.value = undefined
        this.reason = undefined
        this.onResolvedCallbacks = []
        this.onRejectedCallbacks = []

        let resolve = (value) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.value = value
            this.onResolvedCallbacks.forEach(fn => fn())
          }
        }

        let reject = (reason) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.reason = reason
            this.onRejectedCallbacks.forEach(fn => fn())
          }
        }

        try {
          executor(resolve, reject)
        } catch (err) {
          reject(err)
        }
      }

      then(onFulFilled, onRejected) {
        let p2 = new Mypromise((resolve, reject) => {
          let x;
          if (this.state === FULFILLED) {
            setTimeout(() => {
              x = onFulFilled(this.value)
              resolvePromise(p2, x, resolve, reject)
            }, 0)
          }

          if (this.state === REJECTED) {
            x = resolvePromise(this.reason)
            resolvePromise(p2, x, resolve, reject)
          }

          if (this.state === PENDING) {
            this.onResolvedCallbacks.push(() => {
              x = onFulFilled(this.value)
              resolvePromise(p2, x, resolve, reject)
            })
            this.onRejectedCallbacks.push(() => {
              x = onRejected(this.reason)
              resolvePromise(p2, x, resolve, reject)
            })
          }
        })

        return p2
      }
    }

    function resolvePromise(p2, x, resolve, reject) {
      if (p2 === x) {
        return new Error("引用错误")
      }

      if (typeof x === 'object' && x !== null || typeof x === 'function') {
        try {
          let then = x.then
          if (typeof then === 'function') {
            then.call(x, y => {
              resolvePromise(p2, y, resolve, reject)
            }, err => {
              reject(err)
            })
          }
        } catch (err) {
          reject(err)
        }
      } else {
        resolve(x)
      }

    }


    const p = new Mypromise((resolve, reject) => {
      setTimeout(() => {
        resolve(100)
      }, 1000)
    })

    let p2 = p.then((res) => {
      return (res+100)
    })

    p2.then((res) => {
      console.log(res);
    })











    // 2.promise.all
    Promise.myAll = function (promises) {
      let count = 0
      let result = []
      const len = promises.length

      return new Promise((resolve, reject) => {
        if (len === 0) return resolve([])

        promises.forEach((p, i) => {
          Promise.resolve(p).then((res) => {
            count++
            result[i] = res
            if (count === len) {
              resolve(result)
            }
          }).catch(reject)
        })

      })
    }

    // 测试一下
    // const p1 = Promise.resolve(1)
    // const p2 = new Promise((resolve) => {
    //   setTimeout(() => resolve(2), 1000)
    // })
    // const p3 = new Promise((resolve) => {
    //   setTimeout(() => resolve(3), 3000)
    // })

    // const p4 = Promise.reject('err4')
    // const p5 = Promise.reject('err5')

    // // 1. 所有的Promise都成功了
    // const p11 = Promise.myAll([p1, p2, p3])
    //   .then(console.log) // [ 1, 2, 3 ]
    //   .catch(console.log)

    // // 2. 有一个Promise失败了
    // const p12 = Promise.myAll([p1, p2, p4])
    //   .then(console.log)
    //   .catch(console.log) // err4
  </script>
</body>

</html>